package com.ssau.expert.gui.master;

import com.ssau.expert.app.AppContext;
import com.ssau.expert.common.CallableTask;
import com.ssau.expert.common.RuleDTO;
import com.ssau.expert.core.impl.ExpertSystem;
import com.ssau.expert.entity.ShipName;
import com.ssau.expert.entity.ShipProfile;
import com.ssau.expert.gui.common.Controller;
import com.ssau.expert.gui.common.MyControls;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.ArrayList;
import java.util.List;

/**
 * Author: Sergey42
 * Date: 26.11.13 12:53
 */
public class FuzzyExpertFrame extends JFrame implements FuzzyExpertPresenter {

    private Dimension FORM_SIZE = new Dimension(Size.MAIN_WIDTH + Size.RIGHT_PANEL_WIDTH + 30,
            Size.MAIN_HEIGHT + 20 + Size.H_PANEL_HEIGHT);

    private static final String NAME = "Экспертная система. Режим эксперта";

    public static final int RULE_COUNT = 16;
    public static final int COL_COUNT = 10;

    private JTextField[][] textFields = new JTextField[RULE_COUNT][COL_COUNT];

    @Override
    public void init() {
        this.setLayout(null);
        initComponents();
        initDisposition();

        this.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);

        addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                Controller.get().showLoginFrame();
            }
        });
    }

    private void initComponents() {
        JPanel panel = MyControls.createPanel(Size.L_MARGIN, 2 * MyControls.MARGIN,
                Size.MAIN_WIDTH, Size.MAIN_HEIGHT, "");
        panel.setLayout(null);

        initHeaders(panel);
        initRows(panel);
        initFooter(panel);

        JPanel rightPanel = MyControls.createPanel(Size.L_MARGIN + Size.MAIN_WIDTH + MyControls.MARGIN,
                2 * MyControls.MARGIN, Size.RIGHT_PANEL_WIDTH, Size.MAIN_HEIGHT, "");
        rightPanel.setLayout(null);
        initRightPanel(rightPanel);

        add(panel);
        add(rightPanel);
    }

    private void initHeaders(JPanel mainPanel) {

        int height = MyControls.BUTTON_SIZE.height;
        int hPanelHeight = height + 2 * MyControls.MARGIN;
        JPanel header = MyControls.createPanel(MyControls.MARGIN, MyControls.MARGIN, Size.MAIN_WIDTH - 2 * MyControls.MARGIN, hPanelHeight, "");

        //-------------------------------------------------------------------------------------------

        JTextField profileHeader = MyControls.createTextField(0, MyControls.MARGIN, MyControls.MARGIN);
        profileHeader.setText(Resource.PROFILE);
        profileHeader.setEditable(false);
        header.add(profileHeader);

        JTextField autoL1Header = MyControls.createTextField(1, MyControls.MARGIN, MyControls.MARGIN);
        autoL1Header.setText(Resource.AUTO_L_1);
        autoL1Header.setEditable(false);
        header.add(autoL1Header);

        JTextField autoLCF1Header = MyControls.createTextField(2, MyControls.MARGIN, MyControls.MARGIN);
        autoLCF1Header.setText(Resource.AUTO_L_CF_1);
        autoLCF1Header.setEditable(false);
        header.add(autoLCF1Header);

        JTextField autoR1Header = MyControls.createTextField(3, MyControls.MARGIN, MyControls.MARGIN);
        autoR1Header.setText(Resource.AUTO_R_1);
        autoR1Header.setEditable(false);
        header.add(autoR1Header);

        JTextField autoRCF1Header = MyControls.createTextField(4, MyControls.MARGIN, MyControls.MARGIN);
        autoRCF1Header.setText(Resource.AUTO_R_CF_1);
        autoRCF1Header.setEditable(false);
        header.add(autoRCF1Header);

        //-------------------------------------------------------------------------------------------------

        /*
        JTextField autoL2Header = MyControls.createTextField(5, MyControls.MARGIN, MyControls.MARGIN);
        autoL2Header.setText(Resource.AUTO_L_2);
        autoL2Header.setEditable(false);
        header.add(autoL2Header);

        JTextField autoLCF2Header = MyControls.createTextField(6, MyControls.MARGIN, MyControls.MARGIN);
        autoLCF2Header.setText(Resource.AUTO_L_CF_2);
        autoLCF2Header.setEditable(false);
        header.add(autoLCF2Header);

        JTextField autoR2Header = MyControls.createTextField(7, MyControls.MARGIN, MyControls.MARGIN);
        autoR2Header.setText(Resource.AUTO_R_2);
        autoR2Header.setEditable(false);
        header.add(autoR2Header);

        JTextField autoRCF2Header = MyControls.createTextField(8, MyControls.MARGIN, MyControls.MARGIN);
        autoRCF2Header.setText(Resource.AUTO_R_CF_2);
        autoRCF2Header.setEditable(false);
        header.add(autoRCF2Header);
        */
        //-------------------------------------------------------------------------------------------------

        JTextField stuffL1Header = MyControls.createTextField(5, MyControls.MARGIN, MyControls.MARGIN);
        stuffL1Header.setText(Resource.STUFF_L1);
        stuffL1Header.setEditable(false);
        header.add(stuffL1Header);

        JTextField stuffLCF1Header = MyControls.createTextField(6, MyControls.MARGIN, MyControls.MARGIN);
        stuffLCF1Header.setText(Resource.STUFF_L_CF_1);
        stuffLCF1Header.setEditable(false);
        header.add(stuffLCF1Header);

        JTextField stuffR1Header = MyControls.createTextField(7, MyControls.MARGIN, MyControls.MARGIN);
        stuffR1Header.setText(Resource.STUFF_R1);
        stuffR1Header.setEditable(false);
        header.add(stuffR1Header);

        JTextField stuffRCF1Header = MyControls.createTextField(8, MyControls.MARGIN, MyControls.MARGIN);
        stuffRCF1Header.setText(Resource.STUFF_R_CF_1);
        stuffRCF1Header.setEditable(false);
        header.add(stuffRCF1Header);

        //----------------------------------------------------------------------------------------------------
        /*
        JTextField stuffL2Header = MyControls.createTextField(13, MyControls.MARGIN, MyControls.MARGIN);
        stuffL2Header.setText(Resource.STUFF_L2);
        stuffL2Header.setEditable(false);
        header.add(stuffL2Header);

        JTextField stuffLCF2Header = MyControls.createTextField(14, MyControls.MARGIN, MyControls.MARGIN);
        stuffLCF2Header.setText(Resource.STUFF_L_CF_2);
        stuffLCF2Header.setEditable(false);
        header.add(stuffLCF2Header);

        JTextField stuffR2Header = MyControls.createTextField(15, MyControls.MARGIN, MyControls.MARGIN);
        stuffR2Header.setText(Resource.STUFF_R2);
        stuffR2Header.setEditable(false);
        header.add(stuffR2Header);

        JTextField stuffRCF2Header = MyControls.createTextField(16, MyControls.MARGIN, MyControls.MARGIN);
        stuffRCF2Header.setText(Resource.STUFF_R_CF_2);
        stuffRCF2Header.setEditable(false);
        header.add(stuffRCF2Header);
        */
        JTextField shipsTF = MyControls.createTextField(9, MyControls.MARGIN, MyControls.MARGIN);
        shipsTF.setText(Resource.SHIPS);
        shipsTF.setEditable(false);
        header.add(shipsTF);

        mainPanel.add(header);
    }

    private void initRows(JPanel panel) {
        List<RuleDTO> ruleDTOs = AppContext.get().getBean(ExpertSystem.class).getExpertCoeffs();

        for (int i = 0; i < RULE_COUNT; i++) {
            JPanel hPanel = MyControls.createPanel(Size.L_MARGIN, (i + 1) * Size.H_PANEL_HEIGHT + MyControls.MARGIN,
                    Size.MAIN_WIDTH - 2 * MyControls.MARGIN, Size.H_PANEL_HEIGHT, "");

            for (int j = 0; j < COL_COUNT; j++) {
                textFields[i][j] = MyControls.createTextField(j, MyControls.MARGIN, MyControls.MARGIN);
                hPanel.add(textFields[i][j]);

                String val = "1";
                try {
                    val = String.valueOf(ruleDTOs.get(i).values[j]);
                    if ("null".equals(val)) {
                        val = "";
                    }
                } catch (Exception ex) {
                    //Fuck OOP
                }
                textFields[i][j].setText(val);
            }
            panel.add(hPanel);
        }
    }

    private void initFooter(JPanel panel) {
        JPanel hPanel = MyControls.createPanel(Size.L_MARGIN, (RULE_COUNT + 1) * Size.H_PANEL_HEIGHT + MyControls.MARGIN,
                Size.MAIN_WIDTH - 2 * MyControls.MARGIN, Size.H_PANEL_HEIGHT, "");

        JButton buttonOK = MyControls.createButton(Resource.SAVE, MyControls.MARGIN, MyControls.MARGIN);
        buttonOK.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                boolean ok = true;
                List<RuleDTO> ruleDTOList = new ArrayList<RuleDTO>(RULE_COUNT);
                for (int i = 0; i < RULE_COUNT; i++) {
                    RuleDTO ruleDTO = new RuleDTO(i);
                    for (int j = 0; j < COL_COUNT; j++) {
                        try {
                            ruleDTO.values[j] = j == RuleDTO.SHIP
                                    ? textFields[i][j].getText()
                                    : Integer.valueOf(textFields[i][j].getText());
                        } catch (Exception ex) {
                            JOptionPane.showMessageDialog(FuzzyExpertFrame.this,
                                    String.format("Некорректные данные в строке %s столбце %s", i + 1, j + 1),
                                    "Ошибка",
                                    JOptionPane.ERROR_MESSAGE);
                            ok = false;
                            break;
                        }
                    }
                    ruleDTOList.add(ruleDTO);
                }

                /*int i = 1;
                for (RuleDTO ruleDTO : ruleDTOList) {
                    Object[] values = ruleDTO.values;

                    if (
                            ((int) values[RuleDTO.A_L_CF] + (int) values[RuleDTO.A_L_CF2] > 100) ||
                                    ((int) values[RuleDTO.A_R_CF] + (int) values[RuleDTO.A_R_CF2] > 100) ||
                                    ((int) values[RuleDTO.S_L_CF] + (int) values[RuleDTO.S_L_CF2] > 100) ||
                                    ((int) values[RuleDTO.S_R_CF] + (int) values[RuleDTO.S_R_CF2] > 100)
                            ) {
                        JOptionPane.showMessageDialog(FuzzyExpertFrame.this,
                                String.format("Сумма коэффициентов уверенности в правиле %s превышает 100", i),
                                "Ошибка",
                                JOptionPane.ERROR_MESSAGE);
                        ok = false;
                        break;
                    }
                    i++;
                }*/

                if (ok) {
                    CallableTask task = AppContext.get().getBean(ExpertSystem.class).saveExpertCoeffs(ruleDTOList);
                    task.execute();
                }
            }
        });
        hPanel.add(buttonOK);

        panel.add(hPanel);
    }

    private void initRightPanel(JPanel rightPanel) {
        JPanel barrierPanel = MyControls.createPanel(MyControls.MARGIN, MyControls.MARGIN,
                Size.RIGHT_PANEL_WIDTH - 2 * MyControls.MARGIN, Size.BARRIER_PANEL_HEIGHT, "");

        initUndefinedBarrierPanel(barrierPanel);

        JPanel shipInfoPanel = MyControls.createPanel(MyControls.MARGIN, barrierPanel.getHeight() + MyControls.MARGIN,
                Size.RIGHT_PANEL_WIDTH - 2 * MyControls.MARGIN, Size.SHIP_INFO_HEIGHT, "");
        initShipInfoPanel(shipInfoPanel);

        JPanel profilePanel = MyControls.createPanel(MyControls.MARGIN, shipInfoPanel.getHeight() + barrierPanel.getHeight() +
                2 * MyControls.MARGIN, Size.RIGHT_PANEL_WIDTH - 2 * MyControls.MARGIN, Size.PROFILE_INFO_HEIGHT, "");
        initProfilePanel(profilePanel);

        rightPanel.add(barrierPanel);
        rightPanel.add(shipInfoPanel);
        rightPanel.add(profilePanel);
    }

    private void initUndefinedBarrierPanel(JPanel barrierPanel) {
        barrierPanel.setLayout(null);

        JTextField barrierLabel = MyControls.createJTextField(MyControls.MARGIN, MyControls.MARGIN,
                Size.RIGHT_PANEL_WIDTH - 50 - 2 * MyControls.MARGIN, MyControls.BUTTON_SIZE.height, false);
        barrierLabel.setText(Resource.BARRIER);
        barrierPanel.add(barrierLabel);

        final JTextField barrierTF = MyControls.createJTextField(MyControls.MARGIN + barrierLabel.getWidth(), MyControls.MARGIN,
                50 - 2 * MyControls.MARGIN, MyControls.BUTTON_SIZE.height, true);
        barrierTF.setText(String.valueOf(AppContext.get().getBean(ExpertSystem.class).getUndefinedBarrier()));
        barrierPanel.add(barrierTF);

        JButton barrierButton = MyControls.createButton(Resource.SAVE, MyControls.MARGIN, barrierTF.getHeight() + MyControls.MARGIN);
        barrierPanel.add(barrierButton);
        barrierButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                try {
                    String text = barrierTF.getText();
                    int value = Integer.valueOf(text);
                    if (value < 1 || value > 100) {
                        throw new Exception();
                    }

                    AppContext.get().getBean(ExpertSystem.class).setUndefinedBarrier(value);
                } catch (Exception ex) {
                    JOptionPane.showMessageDialog(FuzzyExpertFrame.this,
                            "Некорректные данные",
                            "Ошибка",
                            JOptionPane.ERROR_MESSAGE);
                }
            }
        });
    }

    private void initShipInfoPanel(JPanel shipInfoPanel) {
        shipInfoPanel.setLayout(null);

        int i = 0;
        for (ShipName shipName : ShipName.values()) {
            JTextField tf = MyControls.CreateJTextField(MyControls.MARGIN, MyControls.MARGIN + i * MyControls.BUTTON_SIZE.height, true);
            tf.setText(shipName.getLocalName() + " - " + shipName.getId());
            shipInfoPanel.add(tf);
            i++;
        }
    }

    private void initProfilePanel(JPanel profilePanel) {
        profilePanel.setLayout(null);

        int i = 0;
        for (ShipProfile profile : ShipProfile.values()) {
            JTextField tf = MyControls.CreateJTextField(MyControls.MARGIN, MyControls.MARGIN + i * MyControls.BUTTON_SIZE.height, true);
            tf.setText(profile.getName() + " - " + profile.getId());
            profilePanel.add(tf);
            i++;
        }
    }

    @Override
    public void showFrame() {
        setName(NAME);
        setTitle(NAME);
        setVisible(true);
    }

    private void initDisposition() {
        setSize(FORM_SIZE);
        setLocationRelativeTo(null);
    }

    public static FuzzyExpertFrame get() {
        if (instance == null) {
            instance = new FuzzyExpertFrame();
        }
        return instance;
    }

    private static FuzzyExpertFrame instance;

    private FuzzyExpertFrame() {
    }

    static class Size {
        public static final int RIGHT_PANEL_WIDTH = 210;
        public static final int BARRIER_PANEL_HEIGHT = 60;
        public static final int SHIP_INFO_HEIGHT = ShipName.values().length * MyControls.BUTTON_SIZE.height + 2 * MyControls.MARGIN;
        public static final int PROFILE_INFO_HEIGHT = ShipProfile.values().length * MyControls.BUTTON_SIZE.height + 2 * MyControls.MARGIN;
        static int height = MyControls.BUTTON_SIZE.height;
        static int H_PANEL_HEIGHT = height + 2 * MyControls.MARGIN;

        static final int L_MARGIN = MyControls.MARGIN;

        static int MAIN_WIDTH = (MyControls.X_BUTTON_SIZE.width / 2) * COL_COUNT + 4 * MyControls.MARGIN;
        static int MAIN_HEIGHT = H_PANEL_HEIGHT * (RULE_COUNT + 2) + 2 * MyControls.MARGIN;
    }

    static class Resource {

        public static final String PROFILE = "P";
        public static final String SHIP_NAME = "Название";
        public static final String WATER_VOLUME = "Водоизмещение";
        public static final String AUTO_L_1 = "А L";
        public static final String AUTO_L_2 = "А L2";
        public static final String AUTO_L_CF_1 = "A L CF";
        public static final String AUTO_L_CF_2 = "A LCF2";
        public static final String AUTO_R_1 = "А R";
        public static final String AUTO_R_2 = "А R2";
        public static final String AUTO_R_CF_1 = "A R CF";
        public static final String AUTO_R_CF_2 = "A RCF2";
        public static final String AUTO_2 = "А 2";
        public static final String AUTO_CF_2 = "A CF2";
        public static final String STUFF_L1 = "П L";
        public static final String STUFF_L2 = "П L2";
        public static final String STUFF_L_CF_1 = "П L CF";
        public static final String STUFF_L_CF_2 = "П LCF2";
        public static final String STUFF_R1 = "П R";
        public static final String STUFF_R2 = "П R2";
        public static final String STUFF_R_CF_1 = "П R CF";
        public static final String STUFF_R_CF_2 = "П RCF2";
        public static final String SHIPS = "Корабли";
        public static final String SAVE = "Сохранить";
        public static final String BARRIER = "Порог неизвестного";
    }
}
